package cn.uncode.springcloud.starter.boot.app;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.SimpleCommandLinePropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.env.SystemEnvironmentPropertySource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import cn.uncode.springcloud.starter.boot.app.AppInfo.Profile;


/**
 * 项目启动器，搞定环境变量问题
 *
 * @author juny
 */
public class UncodeApplication {
	
	private static final Logger log = LoggerFactory.getLogger(UncodeApplication.class);

    /**
     * Create an application context
     * java -jar app.jar --spring.profiles.active=prod --server.port=2333
     *
     * @param appName
     *         application name
     * @param source
     *         The sources
     * @return an application context created from the current state
     */
    public static ConfigurableApplicationContext run(String appName, Class<?> source, String... args) {
    	SpringApplicationBuilder builder = createSpringApplicationBuilder(appName, source, args);
        Environment env = builder.run(args).getEnvironment();
        String protocol = "http";
        if (env.getProperty("server.ssl.key-store") != null) {
            protocol = "https";
        }
        try {
			log.info("\n----------------------------------------------------------\n\t" +
			        "Application '{}' is running! Access URLs:\n\t" +
			        "Local: \t\t{}://localhost:{}\n\t" +
			        "External: \t{}://{}:{}\n\t" +
			        "Profile(s): \t{}\n----------------------------------------------------------",
			    env.getProperty("spring.application.name"),
			    protocol,
			    env.getProperty("server.port"),
			    protocol,
			    InetAddress.getLocalHost().getHostAddress(),
			    env.getProperty("server.port"),
			    env.getActiveProfiles());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
        return null;
    }

    public static SpringApplicationBuilder createSpringApplicationBuilder(String appName, Class<?> source, String... args) {
        Assert.hasText(appName, "[appName]服务名不能为空");
        // 读取环境变量，使用spring boot的规则
        ConfigurableEnvironment environment = new StandardEnvironment();
        MutablePropertySources propertySources = environment.getPropertySources();
        propertySources.addFirst(new SimpleCommandLinePropertySource(args));
        propertySources.addLast(new MapPropertySource(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, environment.getSystemProperties()));
        propertySources.addLast(new SystemEnvironmentPropertySource(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, environment.getSystemEnvironment()));
        // 获取配置的环境变量
        String[] activeProfiles = environment.getActiveProfiles();
        // 判断环境:dev、test、pre、prod
        List<String> profiles = Arrays.asList(activeProfiles);
        // 预设的环境
        List<String> presetProfiles = new ArrayList<>(Arrays.asList(Profile.DEV.name, Profile.FAT.name, Profile.PRE.name, Profile.PRD.name));
        // 交集
        presetProfiles.retainAll(profiles);
        // 当前使用
        List<String> activeProfileList = new ArrayList<>(profiles);
        SpringApplicationBuilder builder = new SpringApplicationBuilder(source);
        String profile;
        if (activeProfileList.isEmpty()) {
            // 默认dev开发
            profile = Profile.DEV.name;
            activeProfileList.add(profile);
            builder.profiles(profile);
        } else if (activeProfileList.size() == 1) {
            profile = activeProfileList.get(0);
        } else {
            // 同时存在dev、test、prod环境时
            throw new RuntimeException("同时存在环境变量:[" + StringUtils.arrayToCommaDelimitedString(activeProfiles) + "]");
        }
        Properties props = System.getProperties();
        props.setProperty("spring.application.name", appName);
        //todo 注意:若环境为默认则会污染spring.profiles.active
        props.setProperty("spring.profiles.active", profile);
        props.setProperty("info.app.desc", appName);
        props.setProperty("info.app.env", profile);
        props.setProperty("info.app.name", appName);
        //canary
        String canaryFlag = environment.getProperty("info.canary.flag");
        if (!StringUtils.isEmpty(canaryFlag)) {
        	props.setProperty("info.canary.enabled", "true");
        	props.setProperty("eureka.instance.metadataMap." + AppInfo.APPLICATION_VERSION_METADATA_KEY, canaryFlag);
        }
        //cat client app.name
        props.setProperty("app.name", appName);
        //cat server
        String catServer = environment.getProperty("cat.servers");
        if (!StringUtils.isEmpty(catServer)) {
        	props.setProperty("cat.servers", catServer);
        }
        //apollo client
        props.setProperty(AppInfo.APOLLO_APP_ID, appName);
        props.setProperty("env", profile);
        props.setProperty("apollo.autoUpdateInjectedSpringProperties", "false");
        //cache
        props.setProperty("uncode.cache.storeRegion", appName);
        return builder;
    }
}